﻿using LJ.Abstractions.Exceptions;
using LJ.Abstractions.Extensions;
using LJ.Abstractions.Pack;
using LJ.Abstractions.Pack.Attributes;
using LJ.Host.Abstractions.Exceptions;
using LJ.Host.Abstractions.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;

namespace LJ.Host.Abstractions.Pack.Internal;

public class PackManager : IPackManager
{

    private readonly IReflectionManager _reflectionManager;

    private readonly HashSet<Type> _packTypes = [];

    private readonly List<IPack> _packs = [];

    public PackManager(IReflectionManager reflectionManager)
    {
        _reflectionManager = reflectionManager;


        var packClassTypes = FindPackClassTypes();

        foreach (var packClassType in packClassTypes)
        {
            _packTypes.Add(packClassType);
        }

        var packTypes = FindPackTypes();
        foreach (var packType in packTypes)
        {
            if (!_packTypes.Where(a => a.IsDeriveClassFrom(packType)).Any())
            {
                throw new PackException($"加载模块{packType.FullName}时无法找到依赖模块");
            }
        }


        var packStartupTypes = FindPackStartupTypes();
        foreach (var packStartupType in packStartupTypes)
        {
            var packStartup = (IPackStartup)Activator.CreateInstance(packStartupType)!;
            packStartup.ConfigurePack(this);
        }

        //创建节点
        var packNodes = new List<TopologicalItem<Type>>();
        foreach (var packType in _packTypes)
        {
            CraeteNode(packNodes, packType);
        }
        

        //排序
        var topologicalSortPackNodes = packNodes.TopologicalSort();

        foreach (var packNode in topologicalSortPackNodes)
        {
            _packs.Add((IPack)Activator.CreateInstance(packNode.Value)!);
        }

    }

    public IReadOnlyCollection<IPack> GetPacks()
    {
        return _packs;
    }


    public void Delete<TPack>() where TPack : IPack, new()
    {
        var packType = typeof(TPack);
        _packTypes.Remove(packType);
    }

    private List<Type> FindPackTypes()
    {
        Type[] baseTypes = [typeof(IPack)];
        return _reflectionManager.GetTypes(type => baseTypes.Any(b => type.IsBaseOn(b)));
    }

    private List<Type> FindPackClassTypes()
    {
        Type[] baseTypes = [typeof(IPack)];

        return _reflectionManager.GetTypes(type => baseTypes.Any(b => type.IsDeriveClassFrom(b)));
    }

    private List<Type> FindPackStartupTypes()
    {
        Type[] baseTypes = [typeof(IPackStartup)];
        return _reflectionManager.GetTypes(type => baseTypes.Any(b => type.IsDeriveClassFrom(b)));
    }

    private void CraeteNode(List<TopologicalItem<Type>> packNodes, Type packType, TopologicalItem<Type>? topologicalItem = null)
    {
        var classPackTypes = _packTypes.Where(a => a.IsDeriveClassFrom(packType)).ToList();
        foreach (var classPackType in classPackTypes)
        {
            if (!packNodes.Any(a => a.Value == classPackType))
            {
                CraeteClassNode(packNodes, classPackType, topologicalItem);
            }
        }
    }

    private void CraeteClassNode(List<TopologicalItem<Type>> packNodes, Type packType, TopologicalItem<Type>? topologicalItem)
    {
        var node = new TopologicalItem<Type>(packType);
        var packAttributes = packType.GetAttributes<DependPackAttribute>();
        foreach (var packAttribute in packAttributes)
        {
            CraeteNode(packNodes, packAttribute.DependedPackType, node);
        }
        packNodes.Add(node);
        topologicalItem?.Dependencies.Add(node);
    }
}
